<?php
/**
 *
 * @author wudi
 *
 * 2010-02-26
 */
abstract class doom_core_model {

    /**
     * 分库、分表用的key
     * 一般用于通过一个key进行hash库id和表id的情况
     * profile里多是userid或email
     * @var string
     */
    public $key;
    
    /**
     * model需要的扩展数据
     * @var mixed
     */
    public $extData;
    
    /**
     * 表名
     * 1、分表，此属性不填
     * 2、不分表，需填写此属性
     * @var string
     */
    protected $table;

    /**
     * 表名前缀
     * 1、分表需填写
     * 2、不分表不用填写
     * @var unknown_type
     */
    protected $tablePrefix;

    /**
     * database引擎
     * @var string: (mysql/mysqli/pdo)
     */
    protected $dbEngine = 'doom_model_mysql';

    /**
     * 数据库操作对象，使用注入方式
     * @var base_db_database
     */
    protected $db;

    protected $pk = 'id';

    public $error;
    
    public function __construct() {
        $this->error = new doom_core_error();
    }

    public function getDbObject() {

        return $this->db;
    }

    /**
     * 设置分表用key
     * @param $key
     */
    public function setKey($key) {

        $this->key = $key;
        //如果分表(即table为null)，将table赋值为表前缀+表id
    }

    /**
     * 设扩展数据
     * @param $extData mixed
     */
    public function setExtData($extData) {

        $this->extData = $extData;
    }

    /**
     * 根据分表/不分表策略计算表名
     */
    public function computeTableName() {
        //如果分表，则table为表名前缀+表id
        if ($this->table == NULL) {
            $this->table = $this->tablePrefix . $this->getTableId();
        }
    }

    /**
     * 根据key计算出数据库config的ID
     *
     * 例：
     $dbId = hash($this->key, 1, 32);
     return config_database::$profile[$dbId];
     */
    abstract public function getDbConfig();

    /**
     * 计算表id(各子类需各自实现)，不分表可忽略
     */
    public function getTableId() {
        //TODO 根据key或keyExt计算表id
        return 1;
    }

    public function getDbEngine() {

        return $this->dbEngine;
    }

    public function setDb($db) {

        $this->db = $db;
    }
    
    //####################################################
    

    public function findAll($fields = '*') {

        $sql = "SELECT $fields FROM {$this->table}";
        $rs = $this->db->query($sql);
        if ($rs === FALSE) {
            $this->error->set($this->db->error);
            return FALSE;
        }
        return $rs;
    }

    public function findById($id, $fields = '*') {

        $sql = sprintf("SELECT %s FROM %s WHERE `%s` = '%s'", $fields, $this->table, $this->pk ? $this->pk : 'id', $this->db->escapeString($id));
        $rs = $this->db->query($sql);
        if ($rs === FALSE) {
            $this->error->set($this->db->error);
            return FALSE;
        }
        if (count($rs) > 0) {
            return $rs[0];
        } else {
            return NULL;
        }
    }

    public function findOne($where, $fields = '*') {

        $sql = "SELECT $fields FROM {$this->table} WHERE $where";
        $rs = $this->db->query($sql);
        if ($rs === FALSE) {
            $this->error->set($this->db->error);
            return FALSE;
        }
        if (count($rs) > 0) {
            return $rs[0];
        } else {
            return NULL;
        }
    }

    public function findByIds($ids, $pk = null, $fields = '*') {

        $pk = $pk === null ? $this->pk : $pk;
        $fn = create_function('$v', 'return "\'".mysql_escape_string($v)."\'";');
        if (is_array($ids)) {
            $ids = array_map($fn, $ids);
        }
        $ids = implode(',', $ids);
        $sql = "SELECT $fields FROM {$this->table} WHERE `$pk` IN ($ids)";
        $rs = $this->db->query($sql);
        if ($rs === FALSE) {
            $this->error->set($this->db->error);
            return FALSE;
        }
        return $rs;
    }

    public function findMany($where = '1=1', $orderby = '', $limit = '', $groupby = '') {

        $sql = sprintf("SELECT * FROM %s WHERE %s %s %s %s", $this->table, $where ? $where : '1=1', $orderby ? ' ORDER BY ' . $orderby : '', $groupby ? ' GROUP BY' . $groupby : '', $limit ? $limit : '');
        $rs = $this->db->query($sql);
        if ($rs === FALSE) {
            $this->error->set($this->db->error);
            return FALSE;
        }
        if (count($rs) > 0) {
            return $rs;
        } else {
            return NULL;
        }
    }

    public function count($where = '1=1') {

        $sql = sprintf("SELECT COUNT(*) AS `cnt` FROM %s WHERE %s ", $this->table, $where);
        $r = $this->db->query($sql);
        if ($r === FALSE) {
            $this->error->set($this->db->error);
            return FALSE;
        }
        return $r[0]['cnt'];
    }

    public function add($params = array()) {

        $cond = array();
        foreach ($params as $k => $v) {
            $cond[] = "`" . $k . "` = '" . $this->db->escapeString($v) . "'";
        }
        $sql = sprintf("INSERT INTO `%s`SET %s", $this->table, join(',', $cond));
        $rst = $this->db->insert($sql);
        if ($rst === FALSE) {
            $this->error->set($this->db->error);
            return FALSE;
        }
        return $rst;
    }

    public function update($params, $where = null, $increase = array()) {

        if ($where === null)
            return false;
        $cond = array();
        foreach ($params as $k => $v) {
            if ($k != $key_field && $k != 'id') {
                $cond[] = sprintf("`%s`='%s'", $k, $this->db->escapeString($v));
            }
        }
        
        if ($increase) {
            foreach ($increase as $col => $v)
                $cond[] = sprintf("`%s` = `%s` %s", $col, $col, $v);
        }
        
        $sCond = implode(',', $cond);
        $sql = sprintf("UPDATE `%s` SET %s WHERE %s", $this->table, $sCond, $where);
        $rst = $this->db->update($sql);
        if ($rst === FALSE) {
            $this->error->set($this->db->error);
            return FALSE;
        }
        return $rst;
    }

    public function delete($where = '1=1') {

        $sql = sprintf("DELETE FROM `%s` WHERE %s", $this->table, $where);
        $rst = $this->db->delete($sql);
        if ($rst === FALSE) {
            $this->error->set($this->db->error);
            return FALSE;
        }
        return $rst;
    }

    public function escapeString($s) {

        return $this->db->escapeString($s);
    }

    static public function escapeArray(&$a) {

        foreach ($a as $k => $v) {
            $a[$k] = mysql_escape_string($v);
        }
    }

    public function close() {

        $this->db->close();
    }

    public function getDbInstance() {

        return $this->db;
    }

    static public function closeAll() {

        //TODO
    }
}
